/*
 * Copyright (c) 2016-2017 fulihui.com All right reserved
 * Project: information-core-170307
 * File name: UserIdSingleKeyTableShardingAlgorithm.java
 */

package com.fulihui.information.dal.shard;

import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.SingleKeyTableShardingAlgorithm;
import com.google.common.collect.Range;
import org.apache.commons.lang3.builder.HashCodeBuilder;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author Willard.Hu on 2017/2/17 0017.
 */
public class UserIdSingleKeyTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<String> {

    /**
     * @see SingleKeyTableShardingAlgorithm#doEqualSharding(Collection, ShardingValue)
     */
    @Override
    public String doEqualSharding(Collection<String> tableNames, ShardingValue<String> shardingValue) {
        return findSingle(tableNames, shardingValue.getValue());
    }

    /**
     * @see SingleKeyTableShardingAlgorithm#doInSharding(Collection, ShardingValue)
     */
    @Override
    public Collection<String> doInSharding(Collection<String> tableNames, ShardingValue<String> shardingValue) {
        return findMulti(tableNames, shardingValue.getValues());
    }

    /**
     * @see SingleKeyTableShardingAlgorithm#doBetweenSharding(Collection, ShardingValue)
     */
    @Override
    public Collection<String> doBetweenSharding(Collection<String> tableNames, ShardingValue<String> shardingValue) {
        throw new UnsupportedOperationException("Unsupport between sharding");
    }

    private String findSingle(Collection<String> tableNames, String value) {
        int routeNum = Math.abs(new HashCodeBuilder().append(value).toHashCode()) % 10;
        Optional<String> opt = tableNames.stream()
                .filter(it -> it.endsWith(String.valueOf(routeNum)))
                .findFirst();
        if (!opt.isPresent()) {
            throw new IllegalArgumentException("Sharding Value '" + value + "' could not match tables");
        }
        return opt.get();
    }

    private List<String> findMulti(Collection<String> tableNames, Collection<String> values) {
        return values.stream()
                .map(it -> findSingle(tableNames, it))
                .collect(Collectors.toList());
    }
}
